#ifndef simbatH
#define simbatH

namespace simbat
{

bool Read(int Fd, char *Buf, int Len);
int ReadFromSocketHSL(int sock, void *buf,
   int MaxLen, int MilliSecTimeOut);
int WriteToSocketHSL(int sock, const void *buf,
   int Len, int MilliSecTimeOut);
void SetBaseByPath(const char *Path);

enum HExecFunc { efJob, efRestore, efTrigger, efReloadConfig, efRefreshVarpool, efSetEnv };
enum HNodeRole { nrMaster, nrSlave, nrBackup, nrGateway };

struct HExecInput
{
   HExecFunc Func;
   char FullName[200 + 1];
   char EnvName[80 + 1];
   char JobSeq[8 + 10 + 1];
   char BatchTime[8 + 6 + 1];
   int CmdStrLen;
   int SrcServerId;
   int DesServerId;
   time_t JobStartTime;
   time_t CommStartTime;
   int DitherMs;
   time_t LoopStartTime;
   time_t LoopEndTime;
   int LoopInterval;
   int LoopCount;
   bool RerunFlag;
   bool RestartFlag;
   bool MasterDownFlag;
   HExecInput()
      : Func(efJob), CmdStrLen(0), SrcServerId(0), DesServerId(0), JobStartTime(0),
        CommStartTime(0), DitherMs(0), LoopStartTime(0), LoopEndTime(0), LoopInterval(0), LoopCount(0),
        RerunFlag(false), RestartFlag(false), MasterDownFlag(false)
   {
      FullName[0] = '\0';
      EnvName[0] = '\0';
      JobSeq[0] = '\0';
      BatchTime[0] = '\0';
   }
};

struct HExecOutput
{
   int Rc;
   int Errno;
   long Pid;
   HExecOutput()
      : Rc(0), Errno(0), Pid(0)
   {}
};

enum HBatchStatus
{
   bsBEGIN,
   bsNotStarted = bsBEGIN,
   bsStarted,
   bsPaused,
   bsStopping,
   bsStopped,
   bsEND = bsStopped
};

struct HBatch
{
   HBatchStatus Status;
   char StartTime[8 + 6 + 1];
   char EndTime[8 + 6 + 1];
   char Name[80 + 1];
   char Filler[120];

   HBatch()
   {
      Status = bsNotStarted;
      memset(StartTime, 0, sizeof(StartTime));
      memset(EndTime, 0, sizeof(EndTime));
      memset(Name, 0, sizeof(Name));
      memset(Filler, 0, sizeof(Filler));
   }
};

struct HCtldat
{
   char SeqDate[8 + 1]; // 顺序号日期
   char Filler1[7];
   int Seq;             // 已经分配的顺序号
   int ConfigVersion;   // config.xml 版本号
   int VarpoolVersion;  // var_pool 版本号
   char Filler2[100];

   HCtldat()
   {
      memset(&SeqDate, 0, sizeof(HCtldat));
   }
};

struct HDbHeader
{
   HBatch Batch;
   HCtldat Ctldat;
   int SbtRecCount;
   int VarRecCount;
   int EventRecCount;

   HDbHeader()
    : Batch(), Ctldat(), SbtRecCount(0), VarRecCount(0), EventRecCount(0)
   {}
};

enum HJobType
{
   jtBEGIN,
   jtJob = jtBEGIN,
   jtConnector,
   jtExternJob,
   jtEventWait,
   jtEventFire,
   jtGroup,
   jtTime,
   jtBatch,
   jtEND = jtGroup
};

enum HJobStatus
{
   jsBEGIN,
   jsWaiting = jsBEGIN,
   jsRunning,
   jsSkipped,
   jsFail,
   jsSuccess,
   jsUnknown,
   jsNull,
   jsEND = jsNull
};

struct HJobEvent
{
   char JobName[80 + 1];
   char Time[8 + 6 + 1];
   int PartIdx;    // PartIdx >= 0 : Partition
   int NumOfPart;  // NumOfPart > 0 : Load partitions
   int ServerId;   // Status == jsWait && ServerId == 888 : restart_job
   pid_t Pid;      // Status == jsRunning && Pid == 0 : Run step 1
   HJobStatus Status;
   int RegionId;
   char Filler[12];
   char EyeCatcher[8];
   HJobEvent()
   {
      memset(JobName, 0, sizeof(JobName));
      memset(Time, 0, sizeof(Time));
      PartIdx = -1;
      NumOfPart = 0;
      ServerId = 0;
      Pid = 0;
      RegionId = 0;
      Status = jsWaiting;
      memset(Filler, 0, sizeof(Filler));
      memcpy(EyeCatcher, "SIMBAT\0\0", 8);
   }
};

enum HLogLevel { llDebug, llInfo, llWarn, llError, llFatal };

class HSyslog
{
public :
   void Setup(const HString &LogDir, const HString &LevelStr);
   void Log(const char *SourceFile, int SourceLine,
      HLogLevel Level, const char *LogPoint, const char *Msg);
   bool CheckLevel(HLogLevel Level);
   const char *LogLevelString(HLogLevel Level);
   HLogLevel StringToLogLevel(const HString &Str);
private :
   HString FLogDir;
   HLogLevel FLevel;
};

class HFileLockRead
{
public :
   HFileLockRead(const char *FileName);
   ~HFileLockRead();
   void Lock();
   void Unlock();
private :
   int FLockFd;
   bool FLocked;
};

class HFileLockWrite
{
public :
   HFileLockWrite(const char *FileName);
   ~HFileLockWrite();
   void Lock();
   void Unlock();
private :
   int FLockFd;
   bool FLocked;
};

enum HBackupObjType
{
   boNull,
   boInit,
   boBatchStatus,
   boJobEvents,
   boCtldat,
   boVarpool,
   boConfig,
   boCurrentSbt,
   boEvent,
   boAuth,
   boShr,
   boJobLog,
   boOther
};

enum HLogLocation
{
   llNfs,   // 共享文件系统
   llLocal  // 本地文件系统
};

struct HIniSection
{
   HString Name;
   map<HString, HString> ItemMap;
};

class HCheckBase
{
public :
   HCheckBase(const char *ASimbatBase, const HString &AJobNameDelimiter)
      : SimbatBase(ASimbatBase), JobNameDelimiter(AJobNameDelimiter)
   {}
   bool Load(const char *FileName, char ErrMsg[2048]);

protected :
   bool HasLink(const HString &StartJobName, const HString &EndJobName);
   void GetPreJob(const HString &JobName, const HString &GroupId, vector<HString> &ResultVec, bool WithinGroup);
   bool FindCircuit(const HString &JobName, vector<HString> &Circuit);
   void AddLink(const HString &StartJobName, const HString &EndJobName);
   void AddLink2(const HString &StartJobName, const HString &EndJobName);

   struct job_info
   {
      HString Name;
      HString GroupId;            // group belong to
      HJobType Type;              // job, connector, extern_job
      HString ExternJob;          // if Type == ExternJob
      HString Group;              // if Type == Group
      HString Command;
      vector<HString> Description;
      HString PartitionFile;
      HString Tag;
      set<HString> PreJobs;       // preceding jobs
      set<HString> OriPreJobs;    // preceding jobs, group not expand
      set<HString> SuccJobs;      // succeeding jobs
      bool IsTop;                 // no prejob within group
      bool IsBottom;              // no succjob within group
      int InDegree;
      set<HString> ResourceSetRead;
      set<HString> ResourceSetWrite;
      vector<HString> ExternJobList;
   
      vector<HString> SuccJobVec;
      int SuccJobIdx;
      bool CompletedFlag;
   
      job_info()
         : IsTop(true), IsBottom(true), InDegree(0), SuccJobIdx(0), CompletedFlag(false)
      {}
   };

   HXmlTree Xml;
   map<HString, job_info> Graph;
   map<HString, HXmlTree*> GroupMap;
   HString MainGroupName;
   map<HString, HString> AgentMap;
   vector<HString> GroupNameVec;
   map<HString, bool> HasLinkCache;

   const char *SimbatBase;
   const HString &JobNameDelimiter;
};

struct HBackupInfo
{
   HString Name;
   bool EnableFlag;
   bool PausedFlag;
   bool LogFlag;
   vector<HString> AddrVec;
   HString Addr;
   int Port;

   HBackupInfo()
      : EnableFlag(false), PausedFlag(false), LogFlag(false), Port(0)
   {}
};

bool CallServer(HSyslog &SysLog, int COMM_TIME_OUT, const HString &IpPort, const char *Func, const HString &Object,
   const char *RequestStr, bool SimpleResult, HString &Result, bool WillRetry = false, bool *UnknownFlag = NULL, bool *PSuccFlag = NULL);
bool GetLineFromFile(HSyslog &Syslog, char ErrMsg[8192], const char *FileName, char *Line, bool SkipError = false);
bool GetNumberFromFile(HSyslog &Syslog, char ErrMsg[8192], const char *FileName, int &Number, bool SkipError = false);
bool PutLineToFile(HSyslog &Syslog, char ErrMsg[8192], const char *FileName, const char *Line);
bool PutNumberToFile(HSyslog &Syslog, char ErrMsg[8192], const char *FileName, int Number);
bool SafeSaveXmlToFile(HSyslog &Syslog, char ErrMsg[8192], HXmlTree &Xml, const char *FileName);
HJobType StringToJobType(const HString &String);
HString JobTypeToString(HJobType Type);
const char *JobStatusToString(HJobStatus Status);
HJobStatus StringToJobStatus(const char *String);
bool GetMyId(const char *SimbatBase, int &MyId, HNodeRole &Role, char ErrStr[500 + 1]);
bool SendBackupFile(HSyslog &Syslog, const HString &ShrDir, const HString &LogDir, const char *SimbatBase,
   const char *IpAddr, int Port, HBackupObjType Type, const char *ObjName, long Offset, long Len, const char *ShellFlag = "");
bool LoadIniFile(const char *FileName, vector<HIniSection> &SectionVec, char ErrMsg[8192], bool CommonFlag);
bool FileExist(const HString &Path);
bool ForceMkdir(const HString &Path);
bool CopyFile(const char *SrcFile, const char *DesFile, char ErrStr[500 + 1]);
void LoadBackupInfoFromCfg(HSyslog &Syslog, HXmlTree &Cfg, map<HString, HBackupInfo> &BackupMap);

}; // of namespace simbat

#endif
